//***************************************************************************
//*
//*	File:			Commands.cpp
//*	Description:	Commands implementation for BuildMgr2 AddIn
//*
//***************************************************************************

//
//--------------------------------------------------------------- PRECOMPILED
//

#include "stdafx.h"

//
//--------------------------------------------------- DECLARATION DEPENDENCIES
//

#include "BuildMgr2.h"

//
//--------------------------------------------------------------- DECLARATION
//

#include "Commands.h"

//
//--------------------------------------------------- DEFINITION DEPENDENCIES
//

#include "DialogBuild.h"
#include "DialogConfigure.h"
#include "DialogProgress.h"

//
//-------------------------------------------------------------- PREPROCESSOR
//

#ifdef	_DEBUG
#define	new DEBUG_NEW
#undef	THIS_FILE
static	char THIS_FILE[] = __FILE__;
#endif

//
//---------------------------------------------------------------- DEFINITION
//

static CDialogBuild* g_pdlgBuild	= NULL;

//
//---------------------------------------------------------------------------------------------------
//*************************************     CON/DESTRUCTION     *************************************
//---------------------------------------------------------------------------------------------------
//

//***************************************************************************************************
//**																					  Constructor	  
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Default constructor
//**	@END
//***************************************************************************************************
//inline
CCommands::CCommands()
{
	m_pApplication			= NULL;
	m_pApplicationEventsObj = NULL;
	m_pDebuggerEventsObj	= NULL;
}

//***************************************************************************************************
//**																					   Destructor
//***************************************************************************************************
//**	@DOC		CONSTRUCTION
//**	@MFUNC		Destructor
//**	@END
//***************************************************************************************************
//inline
CCommands::~CCommands()
{
	ASSERT (m_pApplication != NULL);

	m_pApplication->Release();
}

//
//---------------------------------------------------------------------------------------------------
//*****************************************     GET/SET     *****************************************
//---------------------------------------------------------------------------------------------------
//

//***************************************************************************************************
//**																			 SetApplicationObject
//***************************************************************************************************
//**	@DOC		SET
//**	@MFUNC		Sets the pointer to the application's interface
//**	@PARM		[in] Pointer to application's interface
//**	@END
//***************************************************************************************************
//inline
void CCommands::SetApplicationObject( IApplication* pApplication )
{
	m_pApplication = pApplication;

	XApplicationEventsObj::CreateInstance(&m_pApplicationEventsObj);
	m_pApplicationEventsObj->AddRef();
	m_pApplicationEventsObj->Connect(m_pApplication);
	m_pApplicationEventsObj->m_pCommands = this;

	CComPtr<IDispatch> pDebugger;
	if (SUCCEEDED(m_pApplication->get_Debugger(&pDebugger)) 
		&& pDebugger != NULL)
	{
		XDebuggerEventsObj::CreateInstance(&m_pDebuggerEventsObj);
		m_pDebuggerEventsObj->AddRef();
		m_pDebuggerEventsObj->Connect(pDebugger);
		m_pDebuggerEventsObj->m_pCommands = this;
	}
}

//
//---------------------------------------------------------------------------------------------------
//*****************************************     EVENTS     ******************************************
//---------------------------------------------------------------------------------------------------
//

//***************************************************************************************************
//**																			   UnadviseFromEvents
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Disconnects the command interface from the application
//**	@END
//***************************************************************************************************
//inline
void CCommands::UnadviseFromEvents()
{
	ASSERT (m_pApplicationEventsObj != NULL);

	m_pApplicationEventsObj->Disconnect(m_pApplication);
	m_pApplicationEventsObj->Release();
	m_pApplicationEventsObj = NULL;

	if (m_pDebuggerEventsObj != NULL)
	{
		CComPtr<IDispatch> pDebugger;
		VERIFY_OK(m_pApplication->get_Debugger(&pDebugger));
		ASSERT (pDebugger != NULL);
		m_pDebuggerEventsObj->Disconnect(pDebugger);
		m_pDebuggerEventsObj->Release();
		m_pDebuggerEventsObj = NULL;
	}
}

//***************************************************************************************************
//**																				 BeforeBuildStart
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called before a build starts
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::BeforeBuildStart()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																					  BuildFinish
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a build has finished
//**	@COMM		The implementation routes the event through to the currently active build dialog
//**				- if there is one.
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::BuildFinish( long nNumErrors, long nNumWarnings )
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	//
	//	Sad but true: the event won't tell us which configuration has finished
	//	We simply have to assume that BuildFinished events occur in the same order
	//	as the Build commands were issued.
	//
	//	Moreover, DevStudio seems to "hold back" BuildFinished events until there 
	//	are more events to be dispatched.
	//
	//	Therefore the CDialogProgress maintains a queue of pending projets awaiting
	//	the BuildFinish event and upon completion it forces the pending BuildFinish 
	//	events to be dispatched by issuing more (valid) build commands. 
	//	This is done in <mf CDialogProgress::WaitForPending>.
	//

	//
	//	CHECK IF THERE IS A BUILD DIALOG RUNNIUNG
	//
	if ( NULL != ::g_pdlgBuild )
	{
		//
		//	ROUTE THE EVENT THROUGH TO THE BUILD DIALOG
		//
		::g_pdlgBuild->OnBuildFinished( nNumErrors, nNumWarnings );
	}

	//
	//	RETURN SUCCESS
	//
	return S_OK;
}

//***************************************************************************************************
//**																		BeforeApplicationShutDown
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called before the application shts down
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																					 DocumentOpen
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a document is opened
//**	@PARM		[in] Pointer to the document's dispatch interface
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::DocumentOpen( IDispatch* /*theDocument*/ )
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																			  BeforeDocumentClose
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called before a document is closed
//**	@PARM		[in] Pointer to the document's dispatch interface
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::BeforeDocumentClose( IDispatch* /*theDocument*/ )
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																					 DocumentSave
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a document is saved
//**	@PARM		[in] Pointer to the document's dispatch interface
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::DocumentSave( IDispatch* /*theDocument*/ )
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																					  NewDocument
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a new document is created
//**	@PARM		[in] Pointer to the document's dispatch interface
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::NewDocument( IDispatch* /*theDocument*/ )
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																				   WindowActivate
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a window is activated
//**	@PARM		[in] Pointer to the window's dispatch interface
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::WindowActivate( IDispatch* /*theWindow*/ )
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																				 WindowDeactivate
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a window is deactivated
//**	@PARM		[in] Pointer to the window's dispatch interface
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::WindowDeactivate( IDispatch* /*theWindow*/ )
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																				    WorkspaceOpen
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a workspace is opened
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::WorkspaceOpen()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																				   WorkspaceClose
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a workspace is closed
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::WorkspaceClose()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																				     NewWorkspace
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a new workspace is created
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XApplicationEvents::NewWorkspace()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//***************************************************************************************************
//**																				    BreakpointHit
//***************************************************************************************************
//**	@DOC		EVENTS
//**	@MFUNC		Called when a break-point is hit
//**	@PARM		[in] Pointer to the break-point's dispatch interface
//**	@END
//***************************************************************************************************
//inline
HRESULT CCommands::XDebuggerEvents::BreakpointHit( IDispatch* /*pBreakpoint*/ )
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	return S_OK;
}

//
//---------------------------------------------------------------------------------------------------
//****************************************     COMMANDS     *****************************************
//---------------------------------------------------------------------------------------------------
//

//***************************************************************************************************
//**																				BuildMgrConfigure
//***************************************************************************************************
//**	@DOC		COMMANDS
//**	@MFUNC		Called when the user activates the BuildMgr.Configure command
//**	@COMM		Runs the configuration dialog
//**	@END
//***************************************************************************************************
//inline
STDMETHODIMP CCommands::BuildMgrConfigure()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState())

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));

	//
	//	RUN CONFIGURE DIALOG
	//
	CDialogConfigure dlgConfigure;
	dlgConfigure.SetApplication( this->m_pApplication );
	dlgConfigure.DoModal();

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));

	return S_OK;
}

//***************************************************************************************************
//**																					  BuildMgrRun
//***************************************************************************************************
//**	@DOC		COMMANDS
//**	@MFUNC		Called when the user activates the BuildMgr.Run command
//**	@COMM		Runs the build dialog
//**	@END
//***************************************************************************************************
//inline
STDMETHODIMP CCommands::BuildMgrRun()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState())

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));

	//
	//	SETUP BUILD DIALOG
	//
	CDialogBuild dlgBuild;

	//
	//	ATTACH APPLICATION INTERFACE
	//
	dlgBuild.SetApplication( this->m_pApplication );

	//
	//	This is a bit of a hack:
	//
	//		The pointer is used for routing the BuildFinished event 
	//		through to our progress dialog.
	//
	::g_pdlgBuild = &dlgBuild;

	//
	//	SHOW DIALOG
	//
	dlgBuild.DoModal();

	//
	//	Stop routing events	through to the progress dialog
	//
	::g_pdlgBuild = NULL;

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));

	//
	//	CHECK FINISH ACTION
	//
	#ifndef EWX_FORCEIFHUNG
	#define EWX_FORCEIFHUNG     0x00000010
	#endif

	int iResult = 0;

	switch ( dlgBuild.m_enuFinishAction )
	{
		case CDialogBuild::EFinishAction_Quit		:	this->m_pApplication->Quit();																				break;
		case CDialogBuild::EFinishAction_LogOff		:	this->m_pApplication->Quit();	iResult = ::ExitWindowsEx( EWX_LOGOFF					| EWX_FORCE, 0 );	break;
		case CDialogBuild::EFinishAction_PowerOff	:	this->m_pApplication->Quit();	iResult = ::ExitWindows  ( EWX_POWEROFF | EWX_SHUTDOWN  | EWX_FORCE, 0 );	break;
	}
	
	//
	//	THAT'S IT
	//
	return S_OK;
}
